﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="QueryExpression.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   The comparison operator.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Collaboris.DataAccess
{
    /// <summary>
    /// The comparison operator.
    /// </summary>
    public enum ComparisonOperator
    {
        /// <summary>
        /// The eq.
        /// </summary>
        Eq, 

        /// <summary>
        /// The begins.
        /// </summary>
        Begins, 

        /// <summary>
        /// The contains.
        /// </summary>
        Contains, 

        /// <summary>
        /// The greater or equal.
        /// </summary>
        GreaterOrEqual, 

        /// <summary>
        /// The less or equal.
        /// </summary>
        LessOrEqual, 

        /// <summary>
        /// The greater.
        /// </summary>
        Greater, 

        /// <summary>
        /// The less.
        /// </summary>
        Less, 

        /// <summary>
        /// The not equal.
        /// </summary>
        NotEqual, 

        /// <summary>
        /// The date ranges overlap.
        /// </summary>
        DateRangesOverlap, 

        /// <summary>
        /// The is not null.
        /// </summary>
        IsNotNull, 

        /// <summary>
        /// The is null.
        /// </summary>
        IsNull
    }

    /// <summary>
    /// The sort operator.
    /// </summary>
    public enum SortOperator
    {
        /// <summary>
        /// The asc.
        /// </summary>
        Asc, 

        /// <summary>
        /// The desc.
        /// </summary>
        Desc
    }

    /// <summary>
    /// The logical operator.
    /// </summary>
    public enum LogicalOperator
    {
        /// <summary>
        /// The or.
        /// </summary>
        Or, 

        /// <summary>
        /// The and.
        /// </summary>
        And
    }

    /// <summary>
    /// Represents the expression types
    /// </summary>
    public enum ExpressionType
    {
        /// <summary>
        /// Simple operations contain only one operand and no operator.
        /// </summary>
        Simple, 

        /// <summary>
        /// The composite.
        /// </summary>
        Composite
    }

    /// <summary>
    /// Represents the value/type pair to be used to build a CAML query
    /// </summary>
    public class QueryParam
    {
        /// <summary>
        /// The comparison op.
        /// </summary>
        private readonly ComparisonOperator comparisonOp = ComparisonOperator.Eq;

        /// <summary>
        /// The param name.
        /// </summary>
        private readonly string paramName;

        /// <summary>
        /// The param type.
        /// </summary>
        private readonly string paramType;

        /// <summary>
        /// The param value.
        /// </summary>
        private readonly string paramValue;

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryParam"/> class.
        /// </summary>
        /// <param name="paramName">
        /// The param name.
        /// </param>
        /// <param name="paramValue">
        /// The param value.
        /// </param>
        /// <param name="paramType">
        /// The param type.
        /// </param>
        public QueryParam(string paramName, string paramValue, string paramType)
        {
            this.paramValue = paramValue;
            this.paramType = paramType;
            this.paramName = paramName;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryParam"/> class.
        /// </summary>
        /// <param name="paramName">
        /// The param name.
        /// </param>
        /// <param name="paramValue">
        /// The param value.
        /// </param>
        /// <param name="paramType">
        /// The param type.
        /// </param>
        /// <param name="comparisonOperator">
        /// The comparison operator.
        /// </param>
        public QueryParam(string paramName, string paramValue, string paramType, ComparisonOperator comparisonOperator)
        {
            this.paramValue = paramValue;
            this.paramType = paramType;
            this.comparisonOp = comparisonOperator;
            this.paramName = paramName;
        }

        /// <summary>
        /// Gets ComparisonOp.
        /// </summary>
        public ComparisonOperator ComparisonOp
        {
            get
            {
                return this.comparisonOp;
            }
        }

        /// <summary>
        /// Gets ParamValue.
        /// </summary>
        public string ParamValue
        {
            get
            {
                return this.paramValue;
            }
        }

        /// <summary>
        /// Gets ParamType.
        /// </summary>
        public string ParamType
        {
            get
            {
                return this.paramType;
            }
        }

        /// <summary>
        /// Gets ParamName.
        /// </summary>
        public string ParamName
        {
            get
            {
                return this.paramName;
            }
        }
    }

    /// <summary>
    /// Represents a logical expression with left operand and a write operand.
    /// Used to build complex queries. 
    /// </summary>
    public class QueryExpression
    {
        #region Fields

        /// <summary>
        /// The left operand.
        /// </summary>
        private QueryExpression leftOperand;

        /// <summary>
        /// The operator.
        /// </summary>
        private LogicalOperator @operator;

        /// <summary>
        /// The query type.
        /// </summary>
        private ExpressionType queryType;

        /// <summary>
        /// The query value.
        /// </summary>
        private QueryParam queryValue;

        /// <summary>
        /// The right operand.
        /// </summary>
        private QueryExpression rightOperand;

        #endregion

        #region Properties

        /// <summary>
        /// Represents the left operand of the query expression
        /// </summary>
        public QueryExpression LeftOperand
        {
            get
            {
                return this.leftOperand;
            }
           
        }

        /// <summary>
        /// Represents the expression operator
        /// </summary>
        public LogicalOperator Operator
        {
            get
            {
                return this.@operator;
            }
        }

        /// <summary>
        /// Represents the expression right operand
        /// </summary>
        public QueryExpression RightOperand
        {
            get
            {
                return this.rightOperand;
            }
            set
            {
                this.rightOperand = value;
            }
        }

        /// <summary>
        /// Represents the expression type
        /// </summary>
        public ExpressionType QueryType
        {
            get
            {
                return this.queryType;
            }
        }

        /// <summary>
        /// Gets QueryValue.
        /// </summary>
        public QueryParam QueryValue
        {
            get
            {
                return this.queryValue;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExpression"/> class.
        /// </summary>
        /// <param name="leftOperand">
        /// The left operand.
        /// </param>
        /// <param name="logicalOperator">
        /// The logical operator.
        /// </param>
        /// <param name="rightOperand">
        /// The right operand.
        /// </param>
        public QueryExpression(QueryExpression leftOperand, LogicalOperator logicalOperator, QueryExpression rightOperand)
        {
            this.@operator = logicalOperator;
            this.leftOperand = leftOperand;
            this.rightOperand = rightOperand;
            this.queryType = ExpressionType.Composite;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExpression"/> class.
        /// </summary>
        /// <param name="leftOperand">
        /// The left operand.
        /// </param>
        /// <param name="logicalOperator">
        /// The logical operator.
        /// </param>
        /// <param name="rightOperand">
        /// The right operand.
        /// </param>
        public QueryExpression(QueryParam leftOperand, LogicalOperator logicalOperator, QueryParam rightOperand)
        {
            this.@operator = logicalOperator;
            this.leftOperand = new QueryExpression(leftOperand);
            this.rightOperand = new QueryExpression(rightOperand);
            this.queryType = ExpressionType.Composite;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExpression"/> class.
        /// </summary>
        /// <param name="leftOperand">
        /// The left operand.
        /// </param>
        /// <param name="logicalOperator">
        /// The logical operator.
        /// </param>
        /// <param name="rightOperand">
        /// The right operand.
        /// </param>
        public QueryExpression(QueryExpression leftOperand, LogicalOperator logicalOperator, QueryParam rightOperand)
        {
            this.@operator = logicalOperator;
            this.leftOperand = leftOperand;
            this.rightOperand = new QueryExpression(rightOperand);
            this.queryType = ExpressionType.Composite;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExpression"/> class.
        /// </summary>
        /// <param name="leftOperand">
        /// The left operand.
        /// </param>
        /// <param name="logicalOperator">
        /// The logical operator.
        /// </param>
        /// <param name="rightOperand">
        /// The right operand.
        /// </param>
        public QueryExpression(QueryParam leftOperand, LogicalOperator logicalOperator, QueryExpression rightOperand)
        {
            this.@operator = logicalOperator;
            this.leftOperand = new QueryExpression(leftOperand);
            this.rightOperand = rightOperand;
            this.queryType = ExpressionType.Composite;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExpression"/> class.
        /// </summary>
        /// <param name="queryValue">
        /// The query value.
        /// </param>
        public QueryExpression(QueryParam queryValue)
        {
            this.queryValue = queryValue;
            this.queryType = ExpressionType.Simple;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExpression"/> class.
        /// </summary>
        /// <param name="paramName">
        /// The param name.
        /// </param>
        /// <param name="paramValue">
        /// The param value.
        /// </param>
        /// <param name="paramType">
        /// The param type.
        /// </param>
        public QueryExpression(string paramName, string paramValue, string paramType)
        {
            this.queryValue = new QueryParam(paramName, paramValue, paramType);
            this.queryType = ExpressionType.Simple;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="QueryExpression"/> class.
        /// </summary>
        /// <param name="paramName">
        /// The param name.
        /// </param>
        /// <param name="paramValue">
        /// The param value.
        /// </param>
        /// <param name="paramType">
        /// The param type.
        /// </param>
        /// <param name="comparisonOperator">
        /// The comparison operator.
        /// </param>
        public QueryExpression(string paramName, string paramValue, string paramType, ComparisonOperator comparisonOperator)
        {
            this.queryValue = new QueryParam(paramName, paramValue, paramType, comparisonOperator);
            this.queryType = ExpressionType.Simple;
        }

        #endregion
    }
}